/*--- stacks.c ---------------------------- Listing 2-7 ---------
 * Primitives for array-based stacks
 *-------------------------------------------------------------*/

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "stacks.h"

/*---------------------------------------------------------------
 *  clear the stack by pointing the top of the stack
 *  at an invalid item; that is, the stack is empty.
 *-------------------------------------------------------------*/
void ClearStack(Stack *this_stack)
{
    this_stack->top = -1;
}

/*---------------------------------------------------------------
 *  allocate the stack, set the maximum and minimum bounds
 *  on the stack, and show that the stack is empty.
 *-------------------------------------------------------------*/
Stack *CreateStack(int how_many)
{
    Stack *pstk;

    assert(how_many > 0);    /* make sure the size is legal */

    pstk = (Stack *)malloc(sizeof(Stack));
    if (pstk == NULL)
        return (NULL);

    pstk->stack_size = how_many;

    pstk->base = (struct StkElement *)malloc(how_many * sizeof(struct StkElement));

    if (pstk->base == NULL) /* error in allocating stack */
        return (NULL);

   pstk->min_stack = 0;
   pstk->max_stack = how_many - 1;

   ClearStack(pstk);

   return (pstk);
}

/*---------------------------------------------------------------
 *  pop an element from the stack. If stack is not already empty,
 *  copy the element, and decrement stack top.
 *-------------------------------------------------------------*/
int PopElement(Stack *this_stack, struct StkElement *destination)
{
    if (this_stack->top == -1) /* stack empty, return error */
        return (0);

    memmove(destination,
            &((this_stack->base)[this_stack->top]),
            sizeof(struct StkElement));

    this_stack->top -= 1;

    return (1);
}

/*---------------------------------------------------------------
 *  push an element onto the stack. If stack is not already full,
 *  point StackTop to the next slot, and copy the new element.
 *-------------------------------------------------------------*/
int PushElement(Stack *this_stack, struct StkElement *to_push)
{
    /* is stack full? */
    if (this_stack->top == this_stack->max_stack)
        return (0);

    this_stack->top += 1;

    memmove(&((this_stack->base)[this_stack->top]), to_push,
            sizeof(struct StkElement));

    return (1);
}

/*---------------------------------------------------------------
 *  view an element on the stack. Function is passed a value that
 *  specifies the element's position in terms of its distance
 *  from the top. 0 is the top, 1 is the element below the top,
 *  2 is the element below that. If an invalid value is passed,
 *  the function returns NULL; otherwise, it returns a pointer
 *  to the requested element.
 *-------------------------------------------------------------*/
struct StkElement *ViewElement(Stack *this_stack, int which_element)
{
    if (this_stack->top == -1)
        return (NULL);

    if (this_stack->top - which_element < 0)
        return (NULL);

    return (&((this_stack->base)[this_stack->top - which_element]));
}
